package com.cgtu.cgtucalculator.util;

import lombok.extern.slf4j.Slf4j;

import java.util.Set;
import java.util.Stack;
@Slf4j
public class CanCountable {
    private  String targetStr;
    private  int countEnd=0;
    private boolean interceptor=false;
    private int  bracketPri=4;   //表示括号优先级
    private char[] arr;
    private final Stack<Double> doubleStack=new Stack<>();
    private final Stack<Operator> stringStack=new Stack<>();
    public double getResult() {
        return doubleStack.pop();
    }
    /*
    * 读取字符串的操作符
    * */
    public  void readOperator(int start) throws Exception {
        int index=start;
        String target="";
        boolean flag=false;   //判断读入的操作符是否正确
        while (arr[index]<='0'||arr[index]>='9'){
            target+=arr[index];
            if(checkOperator(target)) {
                flag=true;
                index++;
                break;   //匹配到操作符号，退出
            }
            if(target.length()>Operator.Ope_Length) throw new Exception("错误的运算符！");   //避免恶意输入导致程序错误
            index++;
        }
        if(!flag) throw new Exception("错误的运算符!");
        countEnd=index;
    }

    /*
    * 读取字符中的数字
    * */
    public  Double readDoubled(int start)throws Exception{
        StringBuilder res= new StringBuilder();
        int index=start;
        boolean isdot=false;
        while (index<targetStr.length()&&(arr[index]=='.'||(arr[index]>='0'&&arr[index]<='9'))){
            if(arr[index]=='.'){
                if(isdot){
                    throw new Exception("非法输入");
                }
                isdot=true;
            }
            res.append(arr[index]);
            index++;
        }
        countEnd=index;
        return res.toString().equals("") ?null:Double.parseDouble(res.toString());
    }

    /*
    * 判断是否是正确字符串，并进行初步处理
    * */
    public  boolean isErrorStr(String str) throws Exception {
        if(str==null||str.isEmpty()){
            return true;
        }
        targetStr=str;
        arr=str.toCharArray();
        int count=0;
        for(int i=0;i<str.length();i++){
            if(arr[i]==' '){
                count++;
                continue;
            }
            if((arr[i]>='0'&&arr[i]<='9')){
               doubleStack.push(readDoubled(i));
            }
            else {
                readOperator(i);
            }
            i=countEnd-1; //使i到正确的位置
        }
        Operator operator=new Operator("w",0,0);
        while (stringStack.size()!=0){
            if(stringStack.peek().getOpeNum()>doubleStack.size()) throw new Exception("错误使用运算符:"+stringStack.pop().getOperatorStr());
            doResult(operator);
        }
        return count == str.length();
    }
//    public Double doPolishStr() throws Exception {
//        if(stringStack.isEmpty()){
//            if(doubleStack.size()==1){
//                return doubleStack.pop();
//            }
//            throw new Exception("运算错误");
//        }
//        int index=countEnd;
//        for(int i=index;i<targetStr.length();i++){
//            if(arr[i]>='0'&&arr[i]<='9'){
//                doubleStack.push(readDoubled(i));
//                i=countEnd-1; //使i到正确的位置
//            }
//            else {
//                if(arr[i]==')'){
//                    countEnd=i+1;
//                } else{
//                    if(arr[countEnd-1]=='('){
//                        stringStack.push(readOperator(i));
//                        doubleStack.push(doPolishStr());
//                        i=countEnd-1; //使i到正确的位置
//                    }
//                }
//            }
//        }
//
//    }
    /*
    * 比对操作符，压栈，
    * */
    public boolean checkOperator(String targetStr) throws Exception {
        Operator operator;
        switch (targetStr){
            case ")":
                operator=new Operator(targetStr,0,0);
                interceptor=false;
                while (stringStack.peek().getPriority()<4){
                    doResult(operator);
                }
                doResult(operator);
                bracketPri--;
                interceptor= bracketPri != 4;
                return true;
            case "+":
            case "-":
                operator = new Operator(targetStr,1,2);
                doResult(operator);
                stringStack.push(operator);
                return true;
            case "*":
            case "/":
                operator = new Operator(targetStr,2,2);
                doResult(operator);
                stringStack.push(operator);
                return true;
            case "Exp":
            case "^":
            case "Mod":
                operator = new Operator(targetStr,3,2);
                doResult(operator);
                stringStack.push(operator);
                return true;
            case "!":
                stringStack.push(new Operator(targetStr,99,1));
                operator = new Operator("w",0,1);
                doResult(operator);
                return true;
            case "(":
            case "√(":
            case "ln(":
            case "sin(":
            case "cos(":
            case "tan(":
            case "log(":
            case "sqr(":
            case "abs(":
                interceptor=true;
                operator = new Operator(targetStr,bracketPri++,1);
//                doResult(operator);           todo  因为优先级逐级累加   所以不必调用
                stringStack.push(operator);
                return true;
            default:
                return false;

        }
    }
    /*
    * 处理结果
    * */
    Double[] resArr=new Double[Operator.Ope_MaxNUM];
    public void doResult(Operator operator) throws Exception {
//        ||(stringStack.size()==0&&countEnd!=targetStr.length())
        if((stringStack.isEmpty())||stringStack.peek().getOpeNum()>doubleStack.size()){
            return;
        }
        if(stringStack.peek().getPriority()<operator.getPriority()||(interceptor&&stringStack.peek().getPriority()>=4)){  //当前运算符号的优先级别
            return;
        }
        Operator operator1=stringStack.pop();
        for (int i=operator1.getOpeNum();i>0;i--){
            resArr[i-1]=doubleStack.pop();
        }
        getResult(operator1.getOperatorStr());
        //处理 2*2^3+4
        while (stringStack.size()>0&&stringStack.peek().getPriority()>operator.getPriority()&&stringStack.peek().getPriority()<4){
            operator1=stringStack.pop();
            for (int i=operator1.getOpeNum();i>0;i--){
                resArr[i-1]=doubleStack.pop();
            }
            getResult(operator1.getOperatorStr());
        }
    }
    /*
    * 计算部分
    * */
    public void getResult(String operatorStr) throws Exception {
        switch (operatorStr){
            case "(":
                doubleStack.push(resArr[0]);
                break;
            case "+":
                doubleStack.push(resArr[0]+resArr[1]);
                break;
            case "-":
                doubleStack.push(resArr[0]-resArr[1]);
                break;
            case "*":
                doubleStack.push(resArr[0]*resArr[1]);
                break;
            case "/":
                doubleStack.push(resArr[0]/resArr[1]);
                break;
            case "Mod":
                doubleStack.push(resArr[0]%resArr[1]);
                break;
            case "Exp":
                doubleStack.push(resArr[0]*(Math.pow(10,resArr[1])));
                break;
            case "^":
                doubleStack.push(Math.pow(resArr[0],resArr[1]));
                break;
            case "√(":
                doubleStack.push(Math.sqrt(resArr[0]));
                break;
            case "ln(":
                doubleStack.push(Math.log(resArr[0]));
                break;
            case "sin(":
                doubleStack.push(Math.sin(resArr[0]* TransForm.one_Angle));
                break;
            case "cos(":
                doubleStack.push(Math.cos(resArr[0]* TransForm.one_Angle));
                break;
            case "tan(":
                doubleStack.push(Math.tan(resArr[0]* TransForm.one_Angle));
                break;
            case "log(":
                doubleStack.push(Math.log10(resArr[0]));
                break;
            case "abs(":
                doubleStack.push(Math.abs(resArr[0]));
                break;
            case "sqr(":
                doubleStack.push(Math.pow(resArr[0],2));
                break;
            case "!":
                doubleStack.push(SpecialNum.getJieChen(resArr[0]));
                break;
        }
    }

}
